package com.stress.testing.plugin.nosql.redis.util;

import com.stress.testing.plugin.nosql.redis.deserializer.KeyDeserializer;
import com.stress.testing.plugin.nosql.redis.deserializer.StringKeyDeserializer;
import com.stress.testing.plugin.nosql.redis.serializer.KeySerializer;
import com.stress.testing.plugin.nosql.redis.serializer.StringKeySerializer;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public final class ReflectUtills {
    private ReflectUtills() {
    }

    public static Map<String, List<Method>> resolveMethodMap(Class<?> clazz) {
        Map<String, List<Method>> methodMap = new HashMap<>();
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            String methodName = method.getName();
            List<Method> methods = methodMap.get(methodName);
            if (methods == null) {
                methods = new ArrayList<>();
                methodMap.put(methodName, methods);
            }

            methods.add(method);
        }

        return methodMap;
    }

    public static Method getArgsResolveMethod(Method method, Map<String, List<Method>> methodMap) {
        List<Method> methods = methodMap.get(method.getName());
        if (methods != null) {
            for (Method m : methods) {
                if (compareMethod(m, method)) {
                    return m;
                }
            }
        }

        return null;
    }

    public static boolean compareMethod(Method m, Method method) {
        if (!Objects.equals(m.getName(), method.getName())) {
            return false;
        }

        Class<?>[] targetParameterTypes = m.getParameterTypes();
        Class<?>[] resourceParameterTypes = method.getParameterTypes();

        if (targetParameterTypes == null && resourceParameterTypes == null) {
            return true;
        }

        if (targetParameterTypes.length != resourceParameterTypes.length) {
            return false;
        }

        for (int i = 0; i < targetParameterTypes.length; i++) {
            if (!Objects.equals(targetParameterTypes[i], resourceParameterTypes[i])) {
                return false;
            }
        }

        return true;
    }

    public static KeySerializer newKeySerializerInstance(String clazzStr) {
        try {
            return KeySerializer.class.cast(ReflectUtills.class.getClassLoader().loadClass(clazzStr).newInstance());
        } catch (Exception e) {
            return new StringKeySerializer();
        }
    }

    public static KeyDeserializer newKeyDeserializerInstance(String clazzStr) {
        try {
            return KeyDeserializer.class.cast(ReflectUtills.class.getClassLoader().loadClass(clazzStr).newInstance());
        } catch (Exception e) {
            return new StringKeyDeserializer();
        }
    }
}
